package config

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/beevik/etree"
	"strconv"
)

var (
	Stcfg stConfig
)

type stConfig struct {
	ServerName      string `json:"serverName"`
	ServerId        int    `json:"serverId"`
	Monitor         int    `json:"monitor"`
	LocalIp         string `json:"localIp"`
	Url             string `json:"url"`
	ServiceMode     int    `json:"serviceMode"`
	DebugLevel      int    `json:"debugLevel"`
	MismFlag        int    `json:"mismFlag"`
	DBRetryTimes    int    `json:"dbRetryTimes"`
	DBRetryInterval int    `json:"dbRetryInterval"`
	InitRedis       bool   `json:"initRedis"`
	RedisAddr       string `json:"redisAddr"`
	RedisPort       int    `json:"redisPort"`
	RedisDbNum      int    `json:"redisDbNum"`
	DBUser          string `json:"dbUser"`
	DBPwd           string `json:"dbPwd"`
	DBIp            string `json:"dbIp"`
	DBPort          int    `json:"dbPort"`
	DBCharset       string `json:"dbCharset"`
}

func (cfg *stConfig) String() string {
	b, err := json.Marshal(*cfg)
	if err != nil {
		return fmt.Sprintf("%+v", *cfg)
	}

	var out bytes.Buffer

	err = json.Indent(&out, b, "", "    ")
	if err != nil {
		return fmt.Sprintf("%+v", *cfg)
	}

	return out.String()
}

func xmlReadString(node *etree.Element, nodeName string, dflt string) string {
	elem := node.SelectElement(nodeName)
	if elem == nil {
		return ""
	}

	return elem.SelectAttrValue("value", dflt)
}

func xmlReadInt(node *etree.Element, nodeName string, dflt int) int {
	elem := node.SelectElement(nodeName)
	if elem == nil {
		return dflt
	}

	data := elem.SelectAttrValue("value", strconv.Itoa(dflt))

	nValue, err := strconv.ParseInt(data, 10, 32)
	if err != nil {
		fmt.Println("parse int fail:", err)
	}

	return int(nValue)
}

func stoInt(s string) int {
	nValue, err := strconv.ParseInt(s, 10, 32)
	if err != nil {
		fmt.Println("parse int fail:", err)
		return 0
	}
	return int(nValue)
}

func getPropertyMap(node *etree.Element, stcfg *stConfig) {

	p := node.SelectElements("property")
	for _, e := range p {

		atrName := e.SelectAttr("name")
		if atrName == nil {
			fmt.Println("read xml select attr name fail.")
			return
		}

		atrV := e.SelectAttr("value")
		if atrV == nil {
			fmt.Println("read xml select attr value fail.")
			return
		}

		switch atrName.Value {
		case "ServerName":
			stcfg.ServerName = atrV.Value
		case "ServerId":
			stcfg.ServerId = stoInt(atrV.Value)
		case "Monitor":
			stcfg.Monitor = stoInt(atrV.Value)
		case "LocalIp":
			stcfg.LocalIp = atrV.Value
		case "Url":
			stcfg.Url = atrV.Value
		case "ServiceMode":
			stcfg.ServiceMode = stoInt(atrV.Value)
		case "DebugLevel":
			stcfg.DebugLevel = stoInt(atrV.Value)
		case "MismFlag":
			stcfg.DebugLevel = stoInt(atrV.Value)
		case "DBRetryTimes":
			stcfg.DBRetryTimes = stoInt(atrV.Value)
		case "DBRetryInterval":
			stcfg.DBRetryInterval = stoInt(atrV.Value)
		case "RedisAddr":
			stcfg.RedisAddr = atrV.Value
		case "RedisPort":
			stcfg.RedisPort = stoInt(atrV.Value)
		case "RedisDbNum":
			stcfg.RedisDbNum = stoInt(atrV.Value)
		case "InitRedis":
			stcfg.InitRedis, _ = strconv.ParseBool(atrV.Value)
		case "DBUser":
			stcfg.DBUser = atrV.Value
		case "DBPwd":
			stcfg.DBPwd = atrV.Value
		case "DBIP":
			stcfg.DBIp = atrV.Value
		case "DBPort":
			stcfg.DBPort = stoInt(atrV.Value)
		case "CHARSET":
			stcfg.DBCharset = atrV.Value

		}
	}
}

func IsInitRedis() bool {
	return Stcfg.InitRedis
}

// 导出函数首字母必须大写.
func InitConfig(xmlPath string) {

	fmt.Println("read config from:", xmlPath)

	xmlDoc := etree.NewDocument()
	if xmlDoc == nil {
		fmt.Println("create etree fail.")
		return
	}

	err := xmlDoc.ReadFromFile(xmlPath)
	if err != nil {
		fmt.Println("read xml file fail:", err)
		return
	}

	root := xmlDoc.SelectElement("configuration")
	if root == nil {
		fmt.Println("read root(configuration) fail.")
		return
	}

	nodes := root.SelectElements("setting")
	if nodes == nil {
		fmt.Println("read nodes(setting) fail.")
		return
	}

	for _, node := range nodes {

		getPropertyMap(node, &Stcfg)
	}

	nodes = root.SelectElements("mysql")
	if nodes == nil {
		fmt.Println("read nodes(mysql) fail.")
	}

	for _, node := range nodes {
		getPropertyMap(node, &Stcfg)
	}
}

func PrintConfig() {
	fmt.Println("---------------config----------------------")
	fmt.Printf("%s", Stcfg.String())
}
